package com.apes.oap.request.converter;

import com.alibaba.fastjson.JSON;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.AbstractHttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StreamUtils;

import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

/**
 * 功能：
 *
 * @author xul
 * @create 2019-09-12 16:31
 */
public class StringMessageConverter extends AbstractHttpMessageConverter<Object> {

    public static final Charset DEFAULT_CHARSET;
    @Nullable
    private volatile List<Charset> availableCharsets;
    private boolean writeAcceptCharset;

    public StringMessageConverter() {
        this(DEFAULT_CHARSET);
    }

    public StringMessageConverter(Charset defaultCharset) {
        super(defaultCharset, new MediaType[]{MediaType.TEXT_PLAIN, MediaType.ALL});
        this.writeAcceptCharset = true;
    }

    public void setWriteAcceptCharset(boolean writeAcceptCharset) {
        this.writeAcceptCharset = writeAcceptCharset;
    }

    public boolean supports(Class<?> clazz) {
        return true;
    }

    protected Object readInternal(Class<? extends Object> clazz, HttpInputMessage inputMessage) throws IOException {
        Charset charset = this.getContentTypeCharset(inputMessage.getHeaders().getContentType());
        byte[] bytes = StreamUtils.copyToString(inputMessage.getBody(), charset).getBytes();
        try {
            return JSON.parseObject(bytes, 0, bytes.length, Charset.forName("UTF-8").newDecoder(), clazz);
        } catch (Exception e) {
            return null;
        }
    }

    protected Long getContentLength(String str, @Nullable MediaType contentType) {
        Charset charset = this.getContentTypeCharset(contentType);
        return (long)str.getBytes(charset).length;
    }

    protected void writeInternal(Object o, HttpOutputMessage outputMessage) throws IOException {
        if (this.writeAcceptCharset) {
            outputMessage.getHeaders().setAcceptCharset(this.getAcceptedCharsets());
        }

        Charset charset = this.getContentTypeCharset(outputMessage.getHeaders().getContentType());
        StreamUtils.copy(String.valueOf(o), charset, outputMessage.getBody());
    }

    protected List<Charset> getAcceptedCharsets() {
        List<Charset> charsets = this.availableCharsets;
        if (charsets == null) {
            charsets = new ArrayList(Charset.availableCharsets().values());
            this.availableCharsets = (List)charsets;
        }

        return (List)charsets;
    }

    private Charset getContentTypeCharset(@Nullable MediaType contentType) {
        if (contentType != null && contentType.getCharset() != null) {
            return contentType.getCharset();
        } else if (contentType != null && contentType.isCompatibleWith(MediaType.APPLICATION_JSON)) {
            return StandardCharsets.UTF_8;
        } else {
            Charset charset = this.getDefaultCharset();
            Assert.state(charset != null, "No default charset");
            return charset;
        }
    }

    static {
        DEFAULT_CHARSET = StandardCharsets.ISO_8859_1;
    }
}
